package com.libl.controller;

import com.libl.captcha.CaptchaCodeManager;
import com.libl.pojo.DtsAdmin;
import com.libl.service.DtsPermissionService;
import com.libl.service.DtsRoleService;
import com.libl.util.*;
import org.apache.commons.lang3.StringUtils;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.*;
import org.apache.shiro.subject.Subject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;

//首页获取验证码，登录认证
@RestController
@RequestMapping("/admin/auth")
public class AdminAuthController {

    /**
     * 获取验证码：
     * 1，生成验证码；
     * 2，存储在服务器；
     * 3，响应前端。
     */
    @GetMapping("/captchaImage")
    public Object captchaImage() throws IOException {
        //使用自定义工具类生成验证码,验证码长度自定义
        String verifyCode = VerifyCodeUtils.generateVerifyCode(1);
        //生成UUID唯一标识，方便在校验时从服务器获取验证码
        String uuid = UUID.randomUUID().toString();

        //存储在服务器,uuid作为key，验证码作为value，设置存储时间5分钟
        CaptchaCodeManager.addToCache(uuid,verifyCode,5);

        //创建输出流对象
        ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
        //生成验证码图片
        VerifyCodeUtils.outputImage(120,40,outputStream,verifyCode);

        //使用Base64对数据进行转码操作

        //创建返回值数据
        HashMap<String, Object> data = new HashMap<>();
        data.put("img", Base64.encode(outputStream.toByteArray()));
        data.put("uuid",uuid);

        //响应前端
        return ResponseUtil.ok(data);
    }
    /**
     * 登录
     * 接收参数：@RequestBody 把json解析为java对象（map集合）
     * 1，校验验证码
     * 2，执行登录操作
     */
    @PostMapping("/login")
    public Object login(@RequestBody Map<String,String> params){
        //获取用户输入的验证码
        String code = params.get("code");
        String uuid = params.get("uuid");
        String username = params.get("username");
        String password = params.get("password");

        //用服务器端保存的验证码来和用户输入的验证码进行校验
        //从缓存中获取验证码,注意：记得手动清除缓存中的验证码，这里工具类实现了自动清除
        String cacheCode = CaptchaCodeManager.getCachedCaptcha(uuid);
        //忽略大小写，判断验证码是否正确
        if(StringUtils.isEmpty(code)||!code.equalsIgnoreCase(cacheCode)){
            System.out.println("校验失败");
            return AdminResponseUtil.fail(AdminResponseCode.AUTH_CAPTCHA_ERROR);
        }

        //判断用户名和密码是否为空
        if (StringUtils.isEmpty(username)||StringUtils.isEmpty(password)){
            return ResponseUtil.badArgument();
        }

        //shiro框架完成认证和授权
        //获取subject主体对象
        Subject subject = SecurityUtils.getSubject();
        //创建用户名和密码的token对象
        UsernamePasswordToken token = new UsernamePasswordToken(username, password);

        try {
            //登录
            subject.login(token);
            //要想触发realm中的授权功能，必须要先在登录时进行角色判断和权限判断
            System.out.println("超级管理员角色："+subject.hasRole("超级管理员"));
            System.out.println("品牌列表展示权限："+subject.isPermitted("admin:brand:list"));

        } catch (UnknownAccountException e) {
            e.printStackTrace();
            return AdminResponseUtil.fail(AdminResponseCode.ADMIN_UNKNOW_ACCOUNT);
        } catch (LockedAccountException e) {
            e.printStackTrace();
            return AdminResponseUtil.fail(AdminResponseCode.ADMIN_LOCK_ACCOUNT);
        } catch (CredentialsException e) {
            e.printStackTrace();
            return AdminResponseUtil.fail(AdminResponseCode.ADMIN_INVALID_ACCOUNT_OR_PASSWORD);
        } catch (AuthenticationException e) {
            e.printStackTrace();
            return AdminResponseUtil.fail(AdminResponseCode.ADMIN_INVALID_AUTH);
        }
        //下行数据返回SessionID
        return ResponseUtil.ok(subject.getSession().getId());
    }


    /**
     * 获取认证成功的用户信息，只有下行数据
     * data: {
     *     roles : 角色列表
     *     name: 用户名
     *     perms: 权限列表
     *     avatar: 用户头像的地址
     * }
     */
    @Autowired
    DtsRoleService roleService;
    @Autowired
    DtsPermissionService permissionService;

    @GetMapping("/info")
    public Object info() {
        //获取当前登录对象的subject
        Subject subject = SecurityUtils.getSubject();
        //从session中获取用户对象（realm认证方法中返回的对象）
        DtsAdmin admin = (DtsAdmin) subject.getPrincipal();

        String username = admin.getUsername();
        String avatar = admin.getAvatar();
        Integer[] roleIds = admin.getRoleIds();
        Set<String> roles = roleService.findRolesByRoleIds(roleIds);
        Set<String> perms = permissionService.findPermsByRoleIds(roleIds);

        //封装返回值对象
        Map<String,Object> data = new HashMap<>();
        data.put("name", username);
        data.put("avatar", avatar);
        data.put("roles", roles);
        data.put("perms", perms);

        return ResponseUtil.ok(data);
    }
}
